package corelayer;

import corelayer.controllers.FloodingController;
import java.util.Collection;

/**
 * SunSPOT側からは、このクラスを操作することでCoreの各機能を制御できます
 */
public class CoreLayer {

    public static final long DEFAULT_INTERVAL = 1000; // 1秒
    private IRawDevice device;
    private INodeController controller;
    private INode node;
    private PacketBuilder packetBuilder;
    private long intervalMsec;

    /**
     * デバイスを指定してCoreサービスを初期化します
     *
     * @param device 使用するデバイス
     */
    public CoreLayer(IRawDevice device) {
        this(device, new FloodingController());
    }

    /**
     * デバイスと使用するノードコントローラ(アルゴリズム)を指定して初期化します
     *
     * @param device 使用するデバイス
     * @param controller 使用するアルゴリズムを実装するINodeController
     */
    public CoreLayer(IRawDevice device, INodeController controller) {
        this.intervalMsec = -1;
        this.device = device;
        this.controller = controller;
        this.packetBuilder = new PacketBuilder();
        this.node = new Node(new Device(this.device));
    }

    public static void main(String[] args) {
        // ・ヮ・＜ ひつようないです？
    }

    /**
     * スレッドなど非同期処理は環境に依存する可能性があるので、定期的に
     * このメソッドを呼び出して下さい。呼び出す間隔はCoreLayer#getIntervalMsecを通じて取得できます。
     */
    public void interval() {
        this.controller.interval(this.getNode());
    }

    /**
     * INodeController#intervalを実行する間隔で、単位はミリ秒です。
     *
     * @return ミリ秒時間を表す数値
     */
    public long getIntervalMsec() {
        return this.intervalMsec > 0
                ? this.intervalMsec
                : DEFAULT_INTERVAL;
    }

    /**
     * パケットを受信した際に呼び出してください
     *
     * @param data 受け取ったパケット
     */
    public void onPacketReceived(byte[] data) {
        IPacket packet = this.packetBuilder.unpack(data);
        packet.onArrivedAt(this.getNode());
        this.controller.onReceived(this.getNode(), packet);
    }

    /**
     * このノードからメッセージを送信します
     * @param msg 送信するメッセージ
     */
    public void send(IMessage msg) {
        this.node.pushUserMessage(msg);
    }

    /**
     * このノードあてに届いたメッセージを返します
     * @return 
     */
    public Collection<IMessage> getMessages() {
        throw new UnsupportedOperationException("Not implemented");
    }

    public INode getNode() {
        return this.node;
    }
}
